package cn.microservices.cloud.gateway.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.Serializable;
import java.time.Duration;


@Configuration
public class RedisConfiguration {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.lettuce.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.lettuce.pool.max-active}")
    private int maxTotal;
    @Value("${spring.redis.database}")
    private int database;
    @Value("${spring.redis.database0}")
    private int database0;
    @Value("${spring.redis.lettuce.pool.max-wait}")
    private long maxWaitMillis;
    @Value("${spring.redis.lettuce.pool.min-idle}")
    private int minIdle;

    //过期时间1天
    private Duration timeToLive = Duration.ofDays(1);
    /**
     * 申明缓存管理器，会创建一个切面（aspect）并触发Spring缓存注解的切点（pointcut）
     * 根据类或者方法所使用的注解以及缓存的状态，这个切面会从缓存中获取数据，将数据添加到缓存之中或者从缓存中移除某个值

     * @return
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(this.timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer( new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
                .disableCachingNullValues();
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .build();
        return redisCacheManager;
    }

    /**
     * 配置数据源1 基本连接属性
     *
     * @return
     */
    private RedisStandaloneConfiguration getRedisConfig() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
        config.setPassword(password);
        config.setDatabase(database);
        return config;
    }

    /**
     * 配置数据源2 基本连接属性
     *
     * @return
     */
    private RedisStandaloneConfiguration getTokenRedisConfig() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
        config.setPassword(password);
        config.setDatabase(database0);
        return config;
    }
    /**
     * 配置数据源1 连接池配置
     *
     * @return
     */
    private LettuceClientConfiguration getLettuceConfig() {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(maxTotal);
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setMaxWaitMillis(maxWaitMillis);
        return LettucePoolingClientConfiguration.builder().poolConfig(poolConfig).build();
    }

    /**
     * 实例配置
     *
     * @return RedisTemplate
     */
    @Bean("redis")
    public RedisTemplate<String, Serializable> redisTemplate() {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();

        redisTemplate.setKeySerializer(stringSerializer); // redis 序列化数据key的方式
        redisTemplate.setHashKeySerializer(stringSerializer); // redis 序列化数据key的方式
        JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashValueSerializer(serializer);

        LettuceConnectionFactory factory = new LettuceConnectionFactory(getRedisConfig(), getLettuceConfig());
        factory.afterPropertiesSet();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
    /**
     * 实例配置
     *
     * @return RedisTemplate
     */
    @Bean("tokenRedis")
    public RedisTemplate<String, Serializable> tokenRedisTemplate() {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer); // redis 序列化数据key的方式
        redisTemplate.setHashKeySerializer(stringSerializer); // redis 序列化数据key的方式
        JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashValueSerializer(serializer);
        LettuceConnectionFactory factory = new LettuceConnectionFactory(getTokenRedisConfig(), getLettuceConfig());
        factory.afterPropertiesSet();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
    /**
     * 发布/订阅
     * RedisMessageListenerContainer提供订阅消息的多路分发，这样多个订阅可以共享同一个Redis连接.
     */
//    @Bean
//    public RedisMessageListenerContainer redisContainer(LettuceConnectionFactory connectionFactory) {
//        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//        container.setConnectionFactory(connectionFactory);
//        container.addMessageListener(new MyMessageListenCommand(), new ChannelTopic("tenmao.blog.channel"));
//        return container;
//    }

}